package com.tocici.service.impl;

import com.tocici.domain.vo.ArtistVo;
import com.tocici.domain.vo.CateStatVo;
import com.tocici.domain.vo.CategoryVo;
import com.tocici.mapper.ArtistMapper;
import com.tocici.recommender.AprioriRecommender;
import com.tocici.recommender.MusicRecommender;
import com.tocici.service.IArtistService;
import com.tocici.service.ICategoryService;
import org.apache.mahout.cf.taste.common.TasteException;
import org.apache.mahout.cf.taste.recommender.RecommendedItem;
import org.dromara.common.core.utils.MapstructUtils;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.mybatis.core.page.PageQuery;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.RequiredArgsConstructor;
import org.dromara.system.service.ISysConfigService;
import org.springframework.stereotype.Service;
import com.tocici.domain.bo.MusicBo;
import com.tocici.domain.vo.MusicVo;
import com.tocici.domain.Music;
import com.tocici.mapper.MusicMapper;
import com.tocici.service.IMusicService;

import javax.sql.DataSource;
import java.sql.SQLException;
import java.util.List;
import java.util.Map;
import java.util.Collection;

/**
 * 音乐Service业务层处理
 *
 * @author zeratul
 * @date 2025-03-02
 */
@RequiredArgsConstructor
@Service
public class MusicServiceImpl implements IMusicService {

    private final MusicMapper baseMapper;

    private final IArtistService artistService;

    private final ICategoryService categoryService;

    private final DataSource dataSource;

    private final AprioriRecommender aprioriRecommender;

    private final ISysConfigService configService;

    /**
     * 查询音乐
     *
     * @param musicId 主键
     * @return 音乐
     */
    @Override
    public MusicVo queryById(Long musicId){
        return baseMapper.selectVoById(musicId);
    }

    /**
     * 分页查询音乐列表
     *
     * @param bo        查询条件
     * @param pageQuery 分页参数
     * @return 音乐分页列表
     */
    @Override
    public TableDataInfo<MusicVo> queryPageList(MusicBo bo, PageQuery pageQuery) {
        LambdaQueryWrapper<Music> lqw = buildQueryWrapper(bo);
        Page<MusicVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
        return TableDataInfo.build(result);
    }

    /**
     * 查询符合条件的音乐列表
     *
     * @param bo 查询条件
     * @return 音乐列表
     */
    @Override
    public List<MusicVo> queryList(MusicBo bo) {
        LambdaQueryWrapper<Music> lqw = buildQueryWrapper(bo);
        return baseMapper.selectVoList(lqw);
    }

    private LambdaQueryWrapper<Music> buildQueryWrapper(MusicBo bo) {
        Map<String, Object> params = bo.getParams();
        LambdaQueryWrapper<Music> lqw = Wrappers.lambdaQuery();
//        lqw.orderByAsc(Music::getMusicId);
        lqw.eq(StringUtils.isNotBlank(bo.getTitle()), Music::getTitle, bo.getTitle());
        lqw.eq(bo.getAudioUrl() != null, Music::getAudioUrl, bo.getAudioUrl());
        lqw.eq(bo.getImageUrl() != null, Music::getImageUrl, bo.getImageUrl());
        lqw.eq(bo.getDuration() != null, Music::getDuration, bo.getDuration());
        lqw.eq(bo.getArtistId() != null, Music::getArtistId, bo.getArtistId());
        lqw.eq(bo.getCategoryId() != null, Music::getCategoryId, bo.getCategoryId());
        lqw.eq(bo.getPlayCount() != null, Music::getPlayCount, bo.getPlayCount());
        lqw.eq(bo.getIsDeleted() != null, Music::getIsDeleted, bo.getIsDeleted());
        return lqw;
    }

    /**
     * 新增音乐
     *
     * @param bo 音乐
     * @return 是否新增成功
     */
    @Override
    public Boolean insertByBo(MusicBo bo) {
        Music add = MapstructUtils.convert(bo, Music.class);
        validEntityBeforeSave(add);
        boolean flag = baseMapper.insert(add) > 0;
        if (flag) {
            bo.setMusicId(add.getMusicId());
        }
        return flag;
    }

    /**
     * 修改音乐
     *
     * @param bo 音乐
     * @return 是否修改成功
     */
    @Override
    public Boolean updateByBo(MusicBo bo) {
        Music update = MapstructUtils.convert(bo, Music.class);
        validEntityBeforeSave(update);
        return baseMapper.updateById(update) > 0;
    }

    /**
     * 保存前的数据校验
     */
    private void validEntityBeforeSave(Music entity){
        //TODO 做一些数据校验,如唯一约束
    }

    /**
     * 校验并批量删除音乐信息
     *
     * @param ids     待删除的主键集合
     * @param isValid 是否进行有效性校验
     * @return 是否删除成功
     */
    @Override
    public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
        if(isValid){
            //TODO 做一些业务上的校验,判断是否需要校验
        }
        return baseMapper.deleteByIds(ids) > 0;
    }

    @Override
    public List<MusicVo> search(String keyword) {
        LambdaQueryWrapper<Music> lqw = new LambdaQueryWrapper<>();
        lqw.like(Music::getTitle,keyword);
        List<MusicVo> musicVos = baseMapper.selectVoList(lqw);
        musicVos.forEach(musicVo -> {
            ArtistVo artistVo = artistService.queryById(musicVo.getArtistId());
            musicVo.setArtistVo(artistVo);
            CategoryVo categoryVo = categoryService.queryById(musicVo.getCategoryId());
            musicVo.setCategoryVo(categoryVo);
        });
        List<ArtistVo> search = artistService.search(keyword);
        LambdaQueryWrapper<Music> musicLambdaQueryWrapper = new LambdaQueryWrapper<>();
        List<Long> list = search.stream().map(s -> s.getArtistId()).toList();
        list.forEach(id -> {
            MusicBo musicBo = new MusicBo();
            musicBo.setArtistId(id);
            List<MusicVo> musicVosByArtist = this.queryList(musicBo);
            musicVosByArtist.forEach(musicVo -> {
                ArtistVo artistVo = artistService.queryById(musicVo.getArtistId());
                musicVo.setArtistVo(artistVo);
                CategoryVo categoryVo = categoryService.queryById(musicVo.getCategoryId());
                musicVo.setCategoryVo(categoryVo);
            });
            musicVos.addAll(musicVosByArtist);
        });
        return musicVos.stream().distinct().toList();


    }

    @Override
    public List<MusicVo> getNewSongs(Integer i) {
        MusicBo musicBo = new MusicBo();
        LambdaQueryWrapper<Music> lambdaQueryWrapper = buildQueryWrapper(musicBo).orderByDesc(true,Music::getCreateTime,Music::getMusicId);
        List<MusicVo> list = this.baseMapper.selectVoList(lambdaQueryWrapper).stream().limit(i).toList();
        list.forEach(musicVo -> {
            ArtistVo artistVo = artistService.queryById(musicVo.getArtistId());
            musicVo.setArtistVo(artistVo);
            CategoryVo categoryVo = categoryService.queryById(musicVo.getCategoryId());
            musicVo.setCategoryVo(categoryVo);
        });
        return list;
    }

    @Override
    public List<MusicVo> getHotSongs(Integer i) {
        MusicBo musicBo = new MusicBo();
        LambdaQueryWrapper<Music> lambdaQueryWrapper = buildQueryWrapper(musicBo).orderBy(true,false,Music::getPlayCount);
        List<MusicVo> list = this.baseMapper.selectVoList(lambdaQueryWrapper).stream().limit(i).toList();
        list.forEach(musicVo -> {
            ArtistVo artistVo = artistService.queryById(musicVo.getArtistId());
            musicVo.setArtistVo(artistVo);
            CategoryVo categoryVo = categoryService.queryById(musicVo.getCategoryId());
            musicVo.setCategoryVo(categoryVo);
        });
        System.out.println("list = " + list);
        return list;
    }

    @Override
    public List<CateStatVo> getMusicCates() {
        List<CateStatVo> cates = this.baseMapper.getMusicCates();
        return cates;
    }

    @Override
    public List<MusicVo> getRecommend(Long userId) throws TasteException, SQLException {
        String s = configService.selectConfigByKey("app.index.recommend");
        if (!"filter".equals(s)){

            return aprioriRecommender.recommender(userId);
        }else{

            MusicRecommender musicRecommender = new MusicRecommender(dataSource);
            List<Long> list = musicRecommender.recommend(userId, 3).stream().map(RecommendedItem::getItemID).toList();
            System.out.println("list = " + list);
            if (list.isEmpty()){
                LambdaQueryWrapper<Music> musicLambdaQueryWrapper = new LambdaQueryWrapper<>();
                musicLambdaQueryWrapper.orderByDesc(Music::getPlayCount);
                list = this.baseMapper.selectVoList(musicLambdaQueryWrapper).stream().limit(3).map(MusicVo::getMusicId).toList();
            }
            return this.baseMapper.selectVoByIds(list);
        }
    }

}
